/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pe.edu.pucp.sigepa.recocidosimulado.capadatos.impl;

import com.mysema.query.jpa.EclipseLinkTemplates;
import com.mysema.query.jpa.impl.JPAQuery;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.javatuples.Pair;
import pe.edu.pucp.sigepa.recocidosimulado.Controlador.AeropuertoJpaController;
import pe.edu.pucp.sigepa.recocidosimulado.Controlador.EstadoAvionJpaController;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.Aeropuerto;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.Ciudad;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.Continente;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.EstadoAvion;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.Pais;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.QAeropuerto;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.QAvion;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.QPronostico;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.QTipoAvion;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.QVuelo;
import pe.edu.pucp.sigepa.recocidosimulado.Modelo.Vuelo;
import pe.edu.pucp.sigepa.recocidosimulado.capadatos.interfaz.LogicaVuelos;
import pe.edu.pucp.sigepa.recocidosimulado.domain.interfaz.Problema;
import pe.edu.pucp.sigepa.recocidosimulado.domain.interfaz.Solucion;


/**
 *
 * @author carloslengua
 */
public class LogicaVuelosImpl implements LogicaVuelos {
    
    
    @Override
    public Integer obtenerIdContinente(Integer idAeropuerto) {
        
        EntityManagerFactory emf;
        emf = Persistence.createEntityManagerFactory("pe.edu.pucp_motor-generador-rutas-RS2_jar_1.0-SNAPSHOTPU", System.getProperties());
    
        AeropuertoJpaController aeropuertoJpaController = new AeropuertoJpaController(null, emf);
        
        Aeropuerto aeropuerto = aeropuertoJpaController.findAeropuerto(idAeropuerto);
        
        Ciudad ciudad = aeropuerto.getCiudad();
        
        Pais pais = ciudad.getPais();
        
        Continente continente = pais.getContinente();
        
        return continente.getIdcontinente();
    
    }//OK
    
    @Override
    public List<Vuelo> retornarVuelos(Integer idAeropuertoActual, Date fechaHoraSimulacion, Integer nroPaquetes) {
//        Llamada 5, 2012-09-02 08:00:00, 20
//        throw new UnsupportedOperationException("Not supported yet.");
               
        JPAQuery consulta = new JPAQuery(
                                    Persistence.createEntityManagerFactory("pe.edu.pucp_motor-generador-rutas-RS2_jar_1.0-SNAPSHOTPU", System.getProperties())
                                        .createEntityManager(), EclipseLinkTemplates.DEFAULT);
        
        QVuelo vuelo = QVuelo.vuelo;
        QAvion avion = QAvion.avion;
        QTipoAvion tipoAvion = QTipoAvion.tipoAvion;
        QAeropuerto aeropuerto = QAeropuerto.aeropuerto;
        QPronostico pronostico = QPronostico.pronostico;
        QPronostico pronostico2 = new QPronostico("pronostico2");
        
        List<Vuelo> vuelos = consulta.from(vuelo)
                                .innerJoin(vuelo.avion, avion)
                                .innerJoin(avion.tipoAvion, tipoAvion)
                                .innerJoin(vuelo.aeropuertoDestino, aeropuerto)
                                .where(vuelo.aeropuertoOrigen.idaeropuerto.eq(idAeropuertoActual)
                                        .and(vuelo.salidaest.after(fechaHoraSimulacion))
                                        .and((vuelo.numpack.add(nroPaquetes).loe(tipoAvion.cappack))))
//                                        .and(new HibernateSubQuery().from(pronostico)
//                                                .where(pronostico.aeropuerto.eq(vuelo.aeropuertoDestino)
//                                                        .and(pronostico.fechareg.before(fechaHoraSimulacion)))
//                                                .unique(pronostico.nropack.sum()).exists().and(
//                                                    new HibernateSubQuery().from(pronostico2)
//                                                        .where(pronostico2.aeropuerto.eq(vuelo.aeropuertoDestino)
//                                                                .and(pronostico2.fechareg.before(fechaHoraSimulacion)))
//                                                        .unique(pronostico2.nropack.sum()).loe(aeropuerto.cappack.subtract(vuelo.numpack)))))
                                .list(vuelo);
                
        return vuelos;
        
    }
    
    //Obviar escala
    @Override
    public List<Vuelo> obtenerVuelosReemplazantes(Problema problema, Solucion solucion, Integer indiceParVuelos) {
//        throw new UnsupportedOperationException("Not supported yet.");

        JPAQuery consulta = new JPAQuery(
                                    Persistence.createEntityManagerFactory("pe.edu.pucp_motor-generador-rutas-RS2_jar_1.0-SNAPSHOTPU", System.getProperties())
                                        .createEntityManager());     
        
        QVuelo vueloX = QVuelo.vuelo;
        
        QVuelo vuelo0 = new QVuelo("vuelo0");
        QVuelo vuelo1 = new QVuelo("vuelo1");
        QVuelo vuelo2 = new QVuelo("vuelo2");
        QVuelo vuelo3 = new QVuelo("vuelo3");        
        
        QAvion avion = QAvion.avion;
        QTipoAvion tipoAvion = QTipoAvion.tipoAvion;
        QAeropuerto aeropuertoOrigen = new QAeropuerto("aeropuertoOrigen");
        QAeropuerto aeropuertoDestino = new QAeropuerto("aeropuertoDestino");
        QPronostico pronostico = QPronostico.pronostico;
        QPronostico pronostico2 = new QPronostico("pronostico2");
        
        Integer idVuelo1 = solucion.get(indiceParVuelos).getIdvuelo();
        Integer idVuelo2 = solucion.get(indiceParVuelos + 1).getIdvuelo();        
        
        Integer nroPaquetes = problema.getNroPaquetes();
        Date fechaPeticion = problema.getFechaPeticion();
        
        if (0 <= (indiceParVuelos - 1) && (indiceParVuelos + 2) <= solucion.size() - 1 ) {
        
            Integer idVuelo0 = solucion.get(indiceParVuelos - 1).getIdvuelo();
            Integer idVuelo3 = solucion.get(indiceParVuelos + 2).getIdvuelo();
            
            List<Vuelo> vuelos = consulta.from(vueloX, vuelo0, vuelo1, vuelo2, vuelo3)
                                    .innerJoin(vueloX.avion, avion)
                                    .innerJoin(avion.tipoAvion, tipoAvion)
                                    .innerJoin(vueloX.aeropuertoOrigen, aeropuertoOrigen)
                                    .innerJoin(vueloX.aeropuertoDestino, aeropuertoDestino)
                                        .where(vuelo0.idvuelo.eq(idVuelo0)
                                            .and(vuelo1.idvuelo.eq(idVuelo1))
                                            .and(vuelo2.idvuelo.eq(idVuelo2))
                                            .and(vuelo3.idvuelo.eq(idVuelo3))
                                            .and(vueloX.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                            .and(vueloX.aeropuertoDestino.eq(vuelo2.aeropuertoDestino))
                                            .and(vuelo0.llegadaest.before(vueloX.salidaest))
                                            .and(vueloX.llegadaest.before(vuelo3.salidaest))
                                            .and(vueloX.numpack.add(nroPaquetes).loe(tipoAvion.cappack)))
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoOrigen)
//                                                        .and(vuelo0.llegadaest.before(pronostico.fechareg))
//                                                        .and(pronostico.fechareg.before(vueloX.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen.cappack))).notExists())
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoDestino)
//                                                        .and(vueloX.llegadaest.before(pronostico.fechareg))
//                                                        .and(pronostico.fechareg.before(vuelo3.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino.cappack))).notExists()))
                                        .distinct()
                                    .list(vueloX);              
            
            return vuelos;
        }
        
        if (!(0 <= (indiceParVuelos - 1)) && (indiceParVuelos + 2) <= solucion.size() - 1) {
        
//            Integer idVuelo0 = solucion.get(indiceParVuelos - 1).getIdvuelo();
            Integer idVuelo3 = solucion.get(indiceParVuelos + 2).getIdvuelo();
            
            List<Vuelo> vuelos = consulta.from(vueloX, vuelo1, vuelo2, vuelo3)
                                    .innerJoin(vueloX.avion, avion)
                                    .innerJoin(avion.tipoAvion, tipoAvion)
                                    .innerJoin(vueloX.aeropuertoOrigen, aeropuertoOrigen)
                                    .innerJoin(vueloX.aeropuertoDestino, aeropuertoDestino)
                                        .where(vuelo1.idvuelo.eq(idVuelo1)
                                            .and(vuelo2.idvuelo.eq(idVuelo2))
                                            .and(vuelo3.idvuelo.eq(idVuelo3))
                                            .and(vueloX.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                            .and(vueloX.aeropuertoDestino.eq(vuelo2.aeropuertoDestino))
                                            .and(vueloX.salidaest.after(fechaPeticion))
                                            .and(vueloX.llegadaest.before(vuelo3.salidaest))
                                            .and(vueloX.numpack.add(nroPaquetes).loe(tipoAvion.cappack)))
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoOrigen)
//                                                        .and(pronostico.fechareg.after(fechaPeticion))
//                                                        .and(pronostico.fechareg.before(vueloX.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen.cappack))).notExists())
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoDestino)
//                                                        .and(vueloX.llegadaest.before(pronostico.fechareg))
//                                                        .and(pronostico.fechareg.before(vuelo3.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino.cappack))).notExists()))
                                        .distinct()
                                    .list(vueloX);              
            
            return vuelos;
            
        }
        
        if (0 <= (indiceParVuelos - 1) && !((indiceParVuelos + 2) <= solucion.size() - 1)) {
        
            Integer idVuelo0 = solucion.get(indiceParVuelos - 1).getIdvuelo();
//            Integer idVuelo3 = solucion.get(indiceParVuelos + 2).getIdvuelo();
            
            List<Vuelo> vuelos = consulta.from(vueloX, vuelo0, vuelo1, vuelo2)
                                    .innerJoin(vueloX.avion, avion)
                                    .innerJoin(avion.tipoAvion, tipoAvion)
                                    .innerJoin(vueloX.aeropuertoOrigen, aeropuertoOrigen)
                                    .innerJoin(vueloX.aeropuertoDestino, aeropuertoDestino)
                                        .where(vuelo1.idvuelo.eq(idVuelo1)
                                            .and(vuelo2.idvuelo.eq(idVuelo2))
                                            .and(vueloX.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                            .and(vueloX.aeropuertoDestino.eq(vuelo2.aeropuertoDestino))
                                            .and(vueloX.salidaest.after(fechaPeticion))
//                                            .and(vueloX.llegadaest.before(vuelo3.salidaest))
                                            .and(vueloX.numpack.add(nroPaquetes).loe(tipoAvion.cappack)))
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoOrigen)
//                                                        .and(pronostico.fechareg.after(fechaPeticion))
//                                                        .and(pronostico.fechareg.before(vueloX.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen.cappack))).notExists())
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoDestino)
//                                                        .and(pronostico.fechareg.after(vueloX.llegadaest))
////                                                        .and(pronostico.fechareg.before(vuelo3.salidaest)) /*Arreglar*/ Tiempo retencion, politicas de despacho
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino.cappack))).notExists()))
                                        .distinct()
                                    .list(vueloX);              
            
            return vuelos;
        }
        
        if (!(0 <= (indiceParVuelos - 1)) && !((indiceParVuelos + 2) <= solucion.size() - 1)) {
        
//            Integer idVuelo0 = solucion.get(indiceParVuelos - 1).getIdvuelo();
//            Integer idVuelo3 = solucion.get(indiceParVuelos + 2).getIdvuelo();
            
            List<Vuelo> vuelos = consulta.from(vueloX, vuelo1, vuelo2)
                                    .innerJoin(vueloX.avion, avion)
                                    .innerJoin(avion.tipoAvion, tipoAvion)
                                    .innerJoin(vueloX.aeropuertoOrigen, aeropuertoOrigen)
                                    .innerJoin(vueloX.aeropuertoDestino, aeropuertoDestino)
                                        .where(vuelo1.idvuelo.eq(idVuelo1)
                                            .and(vuelo2.idvuelo.eq(idVuelo2))
                                            .and(vueloX.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                            .and(vueloX.aeropuertoDestino.eq(vuelo2.aeropuertoDestino))
                                            .and(vueloX.salidaest.after(fechaPeticion))
//                                            .and(vueloX.llegadaest.before(vuelo3.salidaest))
                                            .and(vueloX.numpack.add(nroPaquetes).loe(tipoAvion.cappack)))
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoOrigen)
//                                                        .and(pronostico.fechareg.after(fechaPeticion))
//                                                        .and(pronostico.fechareg.before(vueloX.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen.cappack))).notExists())
//                                            .and(new HibernateSubQuery().from(pronostico)
//                                                    .where(pronostico.aeropuerto.eq(aeropuertoDestino)
//                                                        .and(pronostico.fechareg.after(vueloX.llegadaest))
////                                                        .and(pronostico.fechareg.before(vuelo3.salidaest))
//                                                        .and(new HibernateSubQuery().from(pronostico2)
//                                                                .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                    .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                    .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino.cappack))).notExists()))
                                        .distinct()
                                    .list(vueloX);              
            
            return vuelos;
        }
        
        return null;
    }//ok

    //Agregar escala
    @Override
    public List<Pair<Vuelo,Vuelo>> retornarParDeVuelosAReemplazar(Problema problema, Solucion solucion, Integer indiceVuelo) {
//        throw new UnsupportedOperationException("Not supported yet.");

        JPAQuery consulta = new JPAQuery(
                                    Persistence.createEntityManagerFactory("pe.edu.pucp_motor-generador-rutas-RS2_jar_1.0-SNAPSHOTPU", System.getProperties())
                                        .createEntityManager());   
        
        QVuelo vuelo0 = new QVuelo("vuelo0");
        QVuelo vuelo1 = new QVuelo("vuelo1");
        QVuelo vuelo2 = new QVuelo("vuelo2");
        QVuelo vueloX1 = new QVuelo("vueloX1");
        QVuelo vueloX2 = new QVuelo("vueloX2");
        
        QAeropuerto aeropuertoOrigen1 = new QAeropuerto("aeropuertoOrigen1");
        QAeropuerto aeropuertoDestino1 = new QAeropuerto("aeropuertoDestino1");
        QAvion avionX1 = new QAvion("avionX1");
        QAvion avionX2 = new QAvion("avionX2"); 
        QTipoAvion tipoAvionX1 = new QTipoAvion("tipoAvionX1");
        QTipoAvion tipoAvionX2 = new QTipoAvion("tipoAvionX2");
        QAeropuerto aeropuertoDestinoX1 = new QAeropuerto("aeropuertoDestinoX1");
        QPronostico pronostico = QPronostico.pronostico;
        QPronostico pronostico2 = new QPronostico("pronostico2");
        
        
        Integer idVuelo1 = solucion.get(indiceVuelo).getIdvuelo();
        
        Integer nroPaquetes = problema.getNroPaquetes();
        Date fechaPeticion = problema.getFechaPeticion();
        
        if ( (0 <= indiceVuelo - 1) && (indiceVuelo + 1 <= solucion.size() - 1)) {
            
            Integer idVuelo0 = solucion.get(indiceVuelo - 1).getIdvuelo();
            Integer idVuelo2 = solucion.get(indiceVuelo + 1).getIdvuelo();            
        
            List<Object[]> listaParesDeVuelos = consulta.from(vuelo0, vuelo1, vuelo2, vueloX1, vueloX2)
//                                                    .innerJoin(vuelo1.aeropuertoOrigen, aeropuertoOrigen1)
//                                                    .innerJoin(vuelo1.aeropuertoDestino, aeropuertoDestino1)
                                                    .innerJoin(vueloX1.avion, avionX1)
                                                    .innerJoin(avionX1.tipoAvion, tipoAvionX1)
//                                                    .innerJoin(vueloX1.aeropuertoDestino, aeropuertoDestinoX1)
                                                    .innerJoin(vueloX2.avion, avionX2)
                                                    .innerJoin(avionX2.tipoAvion, tipoAvionX2)
                                                        .where(vuelo0.idvuelo.eq(idVuelo0)
                                                                .and(vuelo1.idvuelo.eq(idVuelo1))
                                                                .and(vuelo2.idvuelo.eq(idVuelo2))
                                                                .and(vueloX1.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                                                .and(vueloX2.aeropuertoDestino.eq(vuelo1.aeropuertoDestino))
                                                                .and(vueloX1.aeropuertoDestino.eq(vueloX2.aeropuertoOrigen))
                                                                .and(vuelo0.llegadaest.before(vueloX1.salidaest))
                                                                .and(vueloX2.llegadaest.before(vuelo2.salidaest))
                                                                .and(vueloX1.llegadaest.before(vueloX2.salidaest))
                                                                .and(vueloX1.numpack.add(nroPaquetes).loe(tipoAvionX1.cappack))
                                                                .and(vueloX2.numpack.add(nroPaquetes).loe(tipoAvionX2.cappack)))
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoOrigen1)
//                                                                                .and(pronostico.fechareg.after(vuelo0.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX1.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                        .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                            .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                            .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestino1)
//                                                                                .and(pronostico.fechareg.after(vueloX2.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vuelo2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestinoX1)
//                                                                                .and(pronostico.fechareg.after(vueloX1.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestinoX1.cappack))).notExists()))
                                                    .distinct()
                                                .list(vueloX1, vueloX2);  
            
            List<Pair<Vuelo, Vuelo>> paresDeVuelos = new ArrayList<>();
            
            Pair<Vuelo, Vuelo> parDeVuelo_temp = null;
            
            for(Object[] parDeVuelos : listaParesDeVuelos) {
                
                parDeVuelo_temp = new Pair<>((Vuelo) parDeVuelos[0] ,(Vuelo) parDeVuelos[1]);
                paresDeVuelos.add(parDeVuelo_temp);
            
            }
            
            
            return paresDeVuelos;
        }
        
        if ( !(0 <= indiceVuelo - 1) && (indiceVuelo + 1 <= solucion.size() - 1)) {
            
//            Integer idVuelo0 = solucion.get(indiceVuelo - 1).getIdvuelo();
            Integer idVuelo2 = solucion.get(indiceVuelo + 1).getIdvuelo();            
        
            List<Object[]> listaParesDeVuelos = consulta.from(vuelo1, vuelo2, vueloX1, vueloX2)
//                                                    .innerJoin(vuelo1.aeropuertoOrigen, aeropuertoOrigen1)
//                                                    .innerJoin(vuelo1.aeropuertoDestino, aeropuertoDestino1)
                                                    .innerJoin(vueloX1.avion, avionX1)
                                                    .innerJoin(avionX1.tipoAvion, tipoAvionX1)
//                                                    .innerJoin(vueloX1.aeropuertoDestino, aeropuertoDestinoX1)
                                                    .innerJoin(vueloX2.avion, avionX2)
                                                    .innerJoin(avionX2.tipoAvion, tipoAvionX2)
                                                        .where(vuelo1.idvuelo.eq(idVuelo1)
                                                                .and(vuelo2.idvuelo.eq(idVuelo2))
                                                                .and(vueloX1.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                                                .and(vueloX2.aeropuertoDestino.eq(vuelo1.aeropuertoDestino))
                                                                .and(vueloX1.aeropuertoDestino.eq(vueloX2.aeropuertoOrigen))
                                                                .and(vueloX1.salidaest.after(fechaPeticion))
                                                                .and(vueloX2.llegadaest.before(vuelo2.salidaest))
                                                                .and(vueloX1.llegadaest.before(vueloX2.salidaest))
                                                                .and(vueloX1.numpack.add(nroPaquetes).loe(tipoAvionX1.cappack))
                                                                .and(vueloX2.numpack.add(nroPaquetes).loe(tipoAvionX2.cappack)))
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoOrigen1)
//                                                                                .and(pronostico.fechareg.after(fechaPeticion))
//                                                                                .and(pronostico.fechareg.before(vueloX1.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                        .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                            .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                            .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestino1)
//                                                                                .and(pronostico.fechareg.after(vueloX2.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vuelo2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestinoX1)
//                                                                                .and(pronostico.fechareg.after(vueloX1.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestinoX1.cappack))).notExists()))
                                                    .distinct()
                                                .list(vueloX1, vueloX2);  
            
            List<Pair<Vuelo, Vuelo>> paresDeVuelos = new ArrayList<>();
            
            Pair<Vuelo, Vuelo> parDeVuelo_temp = null;
            
            for(Object[] parDeVuelos : listaParesDeVuelos) {
                
                parDeVuelo_temp = new Pair<>((Vuelo) parDeVuelos[0] ,(Vuelo) parDeVuelos[1]);
                paresDeVuelos.add(parDeVuelo_temp);
            
            }
            
            
            return paresDeVuelos;
        }
        
        if ( (0 <= indiceVuelo - 1) && !(indiceVuelo + 1 <= solucion.size() - 1)) {
            
            Integer idVuelo0 = solucion.get(indiceVuelo - 1).getIdvuelo();
//            Integer idVuelo2 = solucion.get(indiceVuelo + 1).getIdvuelo();            
        
            List<Object[]> listaParesDeVuelos = consulta.from(vuelo0, vuelo1, vueloX1, vueloX2)
//                                                    .innerJoin(vuelo1.aeropuertoOrigen, aeropuertoOrigen1)
//                                                    .innerJoin(vuelo1.aeropuertoDestino, aeropuertoDestino1)
                                                    .innerJoin(vueloX1.avion, avionX1)
                                                    .innerJoin(avionX1.tipoAvion, tipoAvionX1)
//                                                    .innerJoin(vueloX1.aeropuertoDestino, aeropuertoDestinoX1)
                                                    .innerJoin(vueloX2.avion, avionX2)
                                                    .innerJoin(avionX2.tipoAvion, tipoAvionX2)
                                                        .where(vuelo0.idvuelo.eq(idVuelo0)
                                                                .and(vuelo1.idvuelo.eq(idVuelo1))
//                                                                .and(vuelo2.idvuelo.eq(idVuelo2))
                                                                .and(vueloX1.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                                                .and(vueloX2.aeropuertoDestino.eq(vuelo1.aeropuertoDestino))
                                                                .and(vueloX1.aeropuertoDestino.eq(vueloX2.aeropuertoOrigen))
                                                                .and(vuelo0.llegadaest.before(vueloX1.salidaest))
//                                                                .and(vueloX2.llegadaest.before(vuelo2.salidaest))
                                                                .and(vueloX1.llegadaest.before(vueloX2.salidaest))
                                                                .and(vueloX1.numpack.add(nroPaquetes).loe(tipoAvionX1.cappack))
                                                                .and(vueloX2.numpack.add(nroPaquetes).loe(tipoAvionX2.cappack)))
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoOrigen1)
//                                                                                .and(pronostico.fechareg.after(vuelo0.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX1.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                        .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                            .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                            .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestino1)
//                                                                                .and(pronostico.fechareg.after(vueloX2.llegadaest))
////                                                                                .and(pronostico.fechareg.before(vuelo2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestinoX1)
//                                                                                .and(pronostico.fechareg.after(vueloX1.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestinoX1.cappack))).notExists()))
                                                    .distinct()
                                                .list(vueloX1, vueloX2);  
            
            List<Pair<Vuelo, Vuelo>> paresDeVuelos = new ArrayList<>();
            
            Pair<Vuelo, Vuelo> parDeVuelo_temp = null;
            
            for(Object[] parDeVuelos : listaParesDeVuelos) {
                
                parDeVuelo_temp = new Pair<>((Vuelo) parDeVuelos[0] ,(Vuelo) parDeVuelos[1]);
                paresDeVuelos.add(parDeVuelo_temp);
            
            }
            
            
            return paresDeVuelos;
        }
       
        if ( !(0 <= indiceVuelo - 1) && !(indiceVuelo + 1 <= solucion.size() - 1)) {
            
//            Integer idVuelo0 = solucion.get(indiceVuelo - 1).getIdvuelo();
//            Integer idVuelo2 = solucion.get(indiceVuelo + 1).getIdvuelo();            
        
            List<Object[]> listaParesDeVuelos = consulta.from(vuelo0, vuelo1, vuelo2, vueloX1, vueloX2)
//                                                    .innerJoin(vuelo1.aeropuertoOrigen, aeropuertoOrigen1)
//                                                    .innerJoin(vuelo1.aeropuertoDestino, aeropuertoDestino1)
                                                    .innerJoin(vueloX1.avion, avionX1)
                                                    .innerJoin(avionX1.tipoAvion, tipoAvionX1)
//                                                    .innerJoin(vueloX1.aeropuertoDestino, aeropuertoDestinoX1)
                                                    .innerJoin(vueloX2.avion, avionX2)
                                                    .innerJoin(avionX2.tipoAvion, tipoAvionX2)
                                                        .where(vuelo1.idvuelo.eq(idVuelo1)
//                                                                .and(vuelo2.idvuelo.eq(idVuelo2))
                                                                .and(vueloX1.aeropuertoOrigen.eq(vuelo1.aeropuertoOrigen))
                                                                .and(vueloX2.aeropuertoDestino.eq(vuelo1.aeropuertoDestino))
                                                                .and(vueloX1.aeropuertoDestino.eq(vueloX2.aeropuertoOrigen))
                                                                .and(vueloX1.salidaest.after(fechaPeticion))
//                                                                .and(vueloX2.llegadaest.before(vuelo2.salidaest))
                                                                .and(vueloX1.llegadaest.before(vueloX2.salidaest))
                                                                .and(vueloX1.numpack.add(nroPaquetes).loe(tipoAvionX1.cappack))
                                                                .and(vueloX2.numpack.add(nroPaquetes).loe(tipoAvionX2.cappack)))
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoOrigen1)
//                                                                                .and(pronostico.fechareg.after(fechaPeticion))
//                                                                                .and(pronostico.fechareg.before(vueloX1.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                        .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                            .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                            .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoOrigen1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestino1)
//                                                                                .and(pronostico.fechareg.after(vueloX2.llegadaest))
////                                                                                .and(pronostico.fechareg.before(vuelo2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestino1.cappack))).notExists())
//                                                                .and(new HibernateSubQuery().from(pronostico)
//                                                                            .where(pronostico.aeropuerto.eq(aeropuertoDestinoX1)
//                                                                                .and(pronostico.fechareg.after(vueloX1.llegadaest))
//                                                                                .and(pronostico.fechareg.before(vueloX2.salidaest))
//                                                                                .and(new HibernateSubQuery().from(pronostico2)
//                                                                                            .where(pronostico2.aeropuerto.eq(pronostico.aeropuerto)
//                                                                                                .and(pronostico2.fechareg.before(pronostico.fechareg)))
//                                                                                                .unique(pronostico2.nropack.sum()).add(nroPaquetes).gt(aeropuertoDestinoX1.cappack))).notExists()))
                                                    .distinct()
                                                .list(vueloX1, vueloX2);  
            
            List<Pair<Vuelo, Vuelo>> paresDeVuelos = new ArrayList<>();
            
            Pair<Vuelo, Vuelo> parDeVuelo_temp = null;
            
            for(Object[] parDeVuelos : listaParesDeVuelos) {
                
                parDeVuelo_temp = new Pair<>((Vuelo) parDeVuelos[0] ,(Vuelo) parDeVuelos[1]);
                paresDeVuelos.add(parDeVuelo_temp);
            
            }
            
            
            return paresDeVuelos;
        }
        
        return null;
        
    }
    
}
